<?php
/************************************************************************
 Omnitrix - PHP Development Framework
 Copyright (C) 2012-2018 amonest(eastson@outlook.com)

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
************************************************************************/

define('DB_FETCHMODE_ORDERED', 1);
define('DB_FETCHMODE_ASSOC', 2);
define('DB_FETCHMODE_OBJECT', 3);
define('DB_FETCHMODE_DEFAULT', DB_FETCHMODE_ASSOC);

$GLOBALS['_XDB'] = null;

function otx_db_connect($params)
{
	if (isset($params['dbtype'])) {
		$dbtype = $params['dbtype'];
		unset($params['dbtype']);
	} else {
		$dbtype = 'mysql';
	}

	$class_name = 'omnitrix_db_' . $dbtype;
	$db = new $class_name();
	$db->connect($params);

	return $db;
}

function otx_db_disconnect($db = null)
{
	$db = null !== $db ? $db : $GLOBALS['_XDB'];
	$db->disconnect();
}

function otx_db_query($sql, $params = array(), $db = null)
{
	$db = null !== $db ? $db : $GLOBALS['_XDB'];
	$db->query($sql, $params);
}

function otx_db_fetch_all($sql, $params = array(), $db = null)
{
	$db = null !== $db ? $db : $GLOBALS['_XDB'];
	return $db->fetch_all($sql, $params);
}

function otx_db_fetch_row($sql, $params = array(), $db = null)
{
	$db = null !== $db ? $db : $GLOBALS['_XDB'];
	return $db->fetch_row($sql, $params);
}

function otx_db_fetch_one($sql, $params = array(), $db = null)
{
	$db = null !== $db ? $db : $GLOBALS['_XDB'];
	return $db->fetch_one($sql, $params);
}

function otx_db_fetch_col($sql, $params = array(), $db = null)
{
	$db = null !== $db ? $db : $GLOBALS['_XDB'];
	return $db->fetch_col($sql, $params);
}

function otx_db_fetch_pairs($sql, $params = array(), $db = null)
{
	$db = null !== $db ? $db : $GLOBALS['_XDB'];
	return $db->fetch_pairs($sql, $params);
}

function otx_db_last_inserted_id($db = null)
{
	$db = null !== $db ? $db : $GLOBALS['_XDB'];
	return $db->last_inserted_id();
}

function otx_db_affected_rows($db = null)
{
	$db = null !== $db ? $db : $GLOBALS['_XDB'];
	return $db->affected_rows();
}

function otx_db_escape_identifier($s, $db = null)
{
	$db = null !== $db ? $db : $GLOBALS['_XDB'];
	return $db->escape_identifier($s);
}

function otx_db_escape_value($s, $db = null)
{
	$db = null !== $db ? $db : $GLOBALS['_XDB'];
	return $db->escape_value($s);
}

function otx_db_escape_array($array, $db = null)
{
	$array = (array) $array;
	foreach ($array as $i => $value) {
		$array[$i] = otx_db_escape_value($value, $db);
	}
	return '(' . implode(',', $array) . ')';
}

function otx_db_insert($table, array $bind, $db = null)
{
	$cols = array();
	$vals = array();

	foreach ($bind as $col => $val) {
		$cols[] = otx_db_escape_identifier($col, $db);
		$vals[] = ':' . $col;
	}

	$sql = "INSERT INTO "
			. otx_db_escape_identifier($table, $db)
			. ' (' . implode(', ', $cols) . ') '
			. 'VALUES (' . implode(', ', $vals) . ')';

	otx_db_query($sql, $bind, $db);
}

function otx_db_replace($table, array $bind, $db = null)
{
	$cols = array();
	$vals = array();

	foreach ($bind as $col => $val) {
		$cols[] = otx_db_escape_identifier($col, $db);
		$vals[] = ':' . $col;
	}

	$sql = "REPLACE INTO "
			. otx_db_escape_identifier($table, $db)
			. ' (' . implode(', ', $cols) . ') '
			. 'VALUES (' . implode(', ', $vals) . ')';

	otx_db_query($sql, $bind, $db);
}

function otx_db_update($table, array $bind, $where = '', $db = null)
{
	$set = array();

	foreach ($bind as $col => $val) {
		$set[] = otx_db_escape_identifier($col, $db) . ' = :' . $col;
	}

	$where = otx_db_where($where, $db);

	$sql = "UPDATE "
			. otx_db_escape_identifier($table, $db)
			. ' SET ' . implode(', ', $set)
			. (($where) ? " WHERE $where" : '');

	otx_db_query($sql, $bind, $db);
}

function otx_db_delete($table, $where = '', $db = null)
{
	$where = otx_db_where($where, $db);

	$sql = "DELETE FROM "
			. otx_db_escape_identifier($table, $db)
			. (($where) ? " WHERE $where" : '');

	otx_db_query($sql, null, $db);
}

function otx_db_where($where, $db = null)
{
	if (empty($where)) {
		return $where;
	}

	if (!is_array($where)) {
		$where = array($where);
	}

	foreach ($where as $cond => &$term) {
		if (is_string($cond)) {
			$term = otx_db_escape_identifier($cond, $db) . ' = ' . otx_db_escape_value($term, $db);
		}

		$term = '(' . $term . ')';
	}

	$where = implode(' AND ', $where);

	return $where;
}

function otx_db_count_sql($sql)
{
	$from_pos = strpos(strtoupper($sql), 'FROM');
	$sql = 'SELECT COUNT(1) ' . substr($sql, $from_pos);

	$order_pos = strpos(strtoupper($sql), 'ORDER BY');
	if (false !== $order_pos) {
		$sql = substr($sql, 0, $order_pos);
	} else {
		$limit_pos = strpos(strtoupper($sql), 'LIMIT');
		if (false !== $limit_pos) {
			$sql = substr($sql, 0, $limit_pos);
		}
	}

	return $sql;
}

function otx_db_list_query($list_sql, $wheres, $default_sort_column, $default_sort_order = 'asc', $row_callback = null)
{
	$info = array(
			'record_count' => null,
			'page_count' => null,
			'sort_column' => null,
			'sort_order' => null,
			'current_page' => null,
			'start_row' => null,
			'end_row' => null,
			'page_size' => 15
	);

	if (!empty($wheres)) {
		if (false !== strpos(strtoupper($list_sql), 'WHERE')) {
			$list_sql .= ' AND ' . otx_db_where($wheres);
		} else {
			$list_sql .= ' WHERE ' . otx_db_where($wheres);
		}
	}

	$count_sql = otx_db_count_sql($list_sql);
	$info['record_count'] = otx_db_fetch_one($count_sql);
	if ($info['record_count'] == 0) {
		return array('rows' => array(), 'pager' => $info);
	}

	$info['page_count'] = ceil($info['record_count'] / $info['page_size']);

	$info['sort_column'] = otx_param_string('sort_column', $default_sort_column);
	$info['sort_order'] = otx_param_string('sort_order', $default_sort_order);
	$list_sql .= ' ORDER BY ' . $info['sort_column'] . ' ' . $info['sort_order'];

	$info['current_page'] = otx_param_int('current_page', 1);
	if ($info['current_page'] > $info['page_count']) {
		$info['current_page'] = $info['page_count'];
	}

	$info['start_row'] = ($info['current_page'] - 1) * $info['page_size'] + 1;
	$info['end_row'] = $info['start_row'] + $info['page_size'] - 1;
	if ($info['end_row'] > $info['record_count']) {
		$info['end_row'] = $info['record_count'];
	}
	$list_sql .= ' LIMIT ' . ($info['start_row'] - 1) . ', ' . $info['page_size'];

	$rows = otx_db_fetch_all($list_sql);
	if (null !== $row_callback) {
		foreach ($rows as $i => $row) {
			$rows[$i] = call_user_func($row_callback, $row);
		}
	}

	return array('rows' => $rows, 'pager' => $info);
}